﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using WPFColorPickerLib;

namespace ButtonBuilder
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static RoutedCommand AutoFocus = new RoutedCommand();

        private System.Windows.Threading.DispatcherTimer PressDownTimer;
        private System.Windows.Threading.DispatcherTimer FocusTimer;

        public MainWindow()
        {
            InitializeComponent();
            
            this.SourceInitialized += new EventHandler(InitializeWindowSource);

            Pages = new List<Controls.Page>();
            Plugins = new List<PluginInfo>();

            PressDownTimer = new System.Windows.Threading.DispatcherTimer();
            PressDownTimer.Interval = TimeSpan.FromSeconds(0.5);
            PressDownTimer.Tick += new EventHandler(PressDownTimer_Tick);

            FocusTimer = new System.Windows.Threading.DispatcherTimer();
            FocusTimer.Interval = TimeSpan.FromSeconds(Properties.Settings.Default.FocusTimerDelay);
            FocusTimer.Tick += new EventHandler(FocusTimer_Tick);

            //Auto Focus Command Hooks
            this.InputBindings.Add(new InputBinding(AutoFocus,
                new KeyGesture(Key.F, ModifierKeys.Control)));
            this.CommandBindings.Add(new CommandBinding(AutoFocus,
                new ExecutedRoutedEventHandler((sender, args) =>
                {
                    FocusTimerEnabled = !FocusTimerEnabled;
                }),
                new CanExecuteRoutedEventHandler((sender, args) =>
                {
                    args.CanExecute = !EditMode; 
                })));

            //Mouse Listener to direct window clicks to buttons in focus.
            //Helpful when Auto Focus enabled with a single click input device.
            Mouse.AddMouseUpHandler(this, (sender, args) =>
            {
                //Make sure we are in the right context
                if (sender == btnClose || EditMode || !FocusTimer.IsEnabled)
                    return;

                //Make sure its the proper type of click
                if (args.ChangedButton != MouseButton.Left)
                    return;

                IInputElement target = Keyboard.FocusedElement;

                //Page Button in focus
                if (target as TextBox != null)
                {
                    target.RaiseEvent(new KeyEventArgs(
                        Keyboard.PrimaryDevice,
                        PresentationSource.FromVisual((Visual)target),
                        0,
                        Key.Enter) { RoutedEvent = Keyboard.KeyDownEvent });

                    target.RaiseEvent(new KeyEventArgs(
                        Keyboard.PrimaryDevice,
                        PresentationSource.FromVisual((Visual)target),
                        1,
                        Key.Enter) { RoutedEvent = Keyboard.KeyUpEvent });

                    args.Handled = true;
                }
                //Normal button in focus
                else if (target as Button != null)
                {
                    target.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

                    args.Handled = true;
                }
            });
        }
        
        #region Properties
        private Point ContextMenuPosition
        {
            get;
            set;
        }

        private ButtonBuilder.Controls.Page CurrentPage
        {
            get;
            set;
        }

        private List<ButtonBuilder.Controls.Page> Pages
        {
            get;
            set;
        }

        public List<PluginInfo> Plugins
        {
            get;
            set;
        }

        public bool FocusTimerEnabled
        {
            get { return Properties.Settings.Default.FocusTimerEnabled; }
            private set
            {
                if (Properties.Settings.Default.FocusTimerEnabled != value)
                {
                    Properties.Settings.Default.FocusTimerEnabled = value;
                    Properties.Settings.Default.Save();

                    if (value)
                        FocusTimer.Start();
                    else
                        FocusTimer.Stop();

                    MessageBox.Show(this, "Auto Focus has been " + (value ? "enabled." : "disabled."),
                        "Auto Focus", MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
        }

        public bool EditMode
        {
            get { return Properties.Settings.Default.EditMode; }
            private set
            {
                if (Properties.Settings.Default.EditMode != value)
                {
                    Properties.Settings.Default.EditMode = value;
                    Properties.Settings.Default.Save();
                }
            }
        }
        #endregion

        #region Public Functions
        public string[] GetPageNames()
        {
            return Pages.Select(p => p.Name)
                .OrderBy(p => p)
                .ToArray();
        }

        #endregion

        #region Private Functions
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Visibility = System.Windows.Visibility.Hidden;

            //Load plugins
            Dispatcher.BeginInvoke(new ThreadStart(() =>
            {
                LoadPlugins();
            }));

            //Load user pages
            Dispatcher.BeginInvoke(new ThreadStart(() =>
            {
                if (ConfirmUserDataFolderExists() && Data.Repository.HasData)
                {
                    Data.Repository.LoadPages().ForEach(p =>
                    {
                        LoadPageData(p);
                    });

                    //Load the startup page.
                    Controls.Page startupPage = Pages.SingleOrDefault(p => p.ShowOnStartup);
                    LoadPage(startupPage ?? Pages.First());
                }
                else
                {
                    LoadPage(new Controls.Page("New Page") { ShowOnStartup = true });
                }

                Visibility = System.Windows.Visibility.Visible;
            }));
        }

        private void LoadPlugins()
        {
            if (!Directory.Exists(Properties.Settings.Default.PluginsFolder))
            {
                MessageBox.Show(this, "Plugins folder does not exist.", "Plugins",
                    MessageBoxButton.OK, MessageBoxImage.Error);

                return;
            }

            Plugins = PluginUtils.FindPlugins(Properties.Settings.Default.PluginsFolder);

            if (Plugins.Count == 0)
            {
                MessageBox.Show(this, "You do not have any plugins installed.", "Plugins", 
                    MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        private void RenamePage(Controls.Page pageToRename, string newName)
        {
            //Update GotoPageAction page name references
            foreach (var page in Pages)
            {
                foreach (var control in page)
                {
                    if (control.ClickAction is Plugin.GotoPageAction)
                    {
                        Plugin.GotoPageAction action = control.ClickAction as Plugin.GotoPageAction;

                        if (action.GetParam("Page") == pageToRename.Name)
                        {
                            action.PutStringParam("Page", newName);
                            page.Save();
                        }
                    }
                }
            }
            
            pageToRename.DeleteFile();
            pageToRename.Name = newName;
            pageToRename.Save();
        }

        private void UpdatePageMenu()
        {
            //Update state of menu items
            itmMakeStartupPage.IsEnabled = !CurrentPage.ShowOnStartup;
            
            //Update the page navigation sub-menu
            mnuViewPage.Items.Clear();

            foreach (var p in Pages.OrderBy(p => p.Name))
            {
                var item = new MenuItem()
                {
                    Header = p.Name,
                    IsChecked = p.Equals(CurrentPage)
                };

                if (p.Dirty)
                {
                    item.FontStyle = FontStyles.Italic;
                }

                item.Click += new RoutedEventHandler(HandleViewPageMenu);
                mnuViewPage.Items.Add(item);
            }
        }

        private void UpdateTitle()
        {
            Title = AssemblyUtils.GetAssemblyInfo().Product;

            if (CurrentPage != null)
            {
                Title += string.Format(" - {0}", CurrentPage.Name + (CurrentPage.Dirty ? "*" : ""));
            }
        }

        internal void LoadPage(Controls.Page page, bool updatePageDisplay = true)
        {
            if (!Pages.Contains(page))
            {
                page.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(PagePropertyChanged);
                Pages.Add(page);
            }

            if (!updatePageDisplay)
                return;

            FocusTimer.Stop();
            FlushPageLayoutChanges(true);
            PageContentPanel.Children.Clear();

            //Adjust location of window based on page
            if (!string.IsNullOrEmpty(page.Location))
            {
                this.Left = Convert.ToDouble(page.Location.Split(',')[0]);
                this.Top = Convert.ToDouble(page.Location.Split(',')[1]);
            }
            else if (CurrentPage != null)
            {
                page.Location = CurrentPage.Location;
            }

            //Adjust size of window based on page
            if (!string.IsNullOrEmpty(page.Size))
            {
                if (page.Size.Equals("Maximized"))
                {
                    this.WindowState = System.Windows.WindowState.Maximized;
                }
                else
                {
                    this.WindowState = System.Windows.WindowState.Normal;
                    this.Width = Convert.ToDouble(page.Size.Split(',')[0]);
                    this.Height = Convert.ToDouble(page.Size.Split(',')[1]);
                }
            }
            else if (CurrentPage != null)
            {
                page.Size = CurrentPage.Size;
            }

            if (page.ImageVisible)
            {
                PageContentPanel.Background = new ImageBrush(
                    new BitmapImage(new Uri(page.ImagePath)));
            }
            else
            {
                PageContentPanel.Background = new SolidColorBrush(
                    (Color)ColorConverter.ConvertFromString(page.Background));
            }

            foreach (var control in page)
            {
                PageContentPanel.Children.Add(control);
                Canvas.SetLeft(control, Math.Max(control.Left, 0));
                Canvas.SetTop(control, Math.Max(control.Top, 0));
            }

            CurrentPage = page;
            UpdateTitle();

            if (!EditMode && FocusTimerEnabled)
                FocusTimer.Start();
        }

        private void LoadPageByName(string pageName)
        {
            Controls.Page page = Pages.SingleOrDefault(p => p.Name == pageName);

            if (page == null)
            {
                if (MessageBox.Show(this, "Page with name \"" + pageName + "\" does not exist. " +
                    "Would you like to create it?", "Page Not Found", 
                    MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.No)
                {
                    return;
                }

                page = new Controls.Page(pageName);
            }

            LoadPage(page);
        }
        
        private void LoadPageData(Data.Page pageData)
        {
            Controls.Page page = new Controls.Page(pageData);
            
            foreach (Controls.Button button in page.Buttons)
            {
                button.Click += new Plugin.ActionHandler(HandlePageButtonClick);
            }

            //Do not update the page display.
            LoadPage(page, false);
        }

        private void PagePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Controls.Page page = sender as Controls.Page;

            if (CurrentPage == page)
            {
                UpdateTitle();
            }

            UpdatePageMenu();
        }

        private void FlushPageLayoutChanges(bool resetRenderTransform)
        {
            if (CurrentPage == null)
                return;

            //Flush position data to properties of control

            foreach (var control in CurrentPage)
            {
                Point p = new Point(Canvas.GetLeft(control), Canvas.GetTop(control));
                control.Top = control.RenderTransform.Transform(p).Y;
                control.Left = control.RenderTransform.Transform(p).X;

                if (resetRenderTransform) 
                    control.RenderTransform = Transform.Identity;
            }
        }

        private bool ConfirmUserDataFolderExists()
        {
            if (string.IsNullOrWhiteSpace(Data.Repository.UserDataFolder) || 
                !Directory.Exists(Data.Repository.UserDataFolder))
            {
                var dlg = new System.Windows.Forms.FolderBrowserDialog();
                dlg.Description = "Please select a folder for storing user data.";
                dlg.RootFolder = Environment.SpecialFolder.MyDocuments;

                if (dlg.ShowDialog(this.GetIWin32Window()) == System.Windows.Forms.DialogResult.OK)
                {
                    Data.Repository.CreateUserDataFolder(dlg.SelectedPath);
                }
                else
                {
                    return false;
                }
            }
            
            return true;
        }

        public void RemovePageButton(Controls.Button b)
        {
            PageContentPanel.Children.Remove(b);
            CurrentPage.Remove(b);
        }
        #endregion
        
        #region ContextMenu Handlers
        private void CloseCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void CloseExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            Close();
        }

        private void SavePageCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void SavePageExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            itmSavePage_Click(this, null);
        }

        private void NewPageCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void NewPageExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            itmNewPage_Click(this, null);
        }

        private void HandleViewPageMenu(object sender, RoutedEventArgs e)
        {
            LoadPageByName((sender as MenuItem).Header.ToString());
        }

        private void HandlePageButtonClick(object sender, Plugin.ActionEventArgs e)
        {
            if (e.Result.Source is Plugin.GotoPageAction)
            {
                LoadPageByName(e.Result.NextPage);
            }
            else if (e.Result.Error != null)
            {
                MessageBox.Show(this, e.Result.Error.Message, 
                    e.Result.Source.Name + " Plugin Error", 
                    MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void itmEditMode_Click(object sender, RoutedEventArgs e)
        {
            EditMode = !EditMode;
        }

        private void itmNewPage_Click(object sender, RoutedEventArgs e)
        {
            string pageName = null;
            string prompt = "New page name:";

            do
            {
                pageName = InputDialog.ShowDialog(this, prompt, "New Page");

                if (!string.IsNullOrWhiteSpace(pageName) && Pages.SingleOrDefault(p => p.Name == pageName) == null)
                {
                    LoadPage(new Controls.Page(pageName));
                    break;
                }
                else
                {
                    prompt = "Page already exists. New page name:";
                }
            } while (pageName != null);
        }

        private void itmRenamePage_Click(object sender, RoutedEventArgs e)
        {
            string newName = null;
            string prompt = "New page name:";

            do
            {
                newName = InputDialog.ShowDialog(this, prompt, "Rename Page", CurrentPage.Name);

                if (!string.IsNullOrWhiteSpace(newName) && Pages.SingleOrDefault(p => p.Name == newName) == null)
                {
                    RenamePage(CurrentPage, newName);
                    UpdateTitle();
                    break;
                }
                else
                {
                    prompt = "Page already exists. New page name:";
                }
            } while (newName != null);
        }

        private void itmBackgroundColor_Click(object sender, RoutedEventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            colorDialog.Owner = this;

            if ((bool)colorDialog.ShowDialog())
            {
                PageContentPanel.Background = new SolidColorBrush(colorDialog.SelectedColor);
                CurrentPage.Background = colorDialog.SelectedColor.ToString();
                CurrentPage.ImageVisible = false;
                CurrentPage.Dirty = true;

                UpdateTitle();
            }
        }

        private void itmBackgroundPicture_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".png";
            dlg.Filter = "Image (.png)|*.png";

            if (dlg.ShowDialog(this) == true)
            {
                string imagePath = dlg.FileName;

                PageContentPanel.Background = new ImageBrush(new BitmapImage(new Uri(imagePath)));

                CurrentPage.ImagePath = imagePath;
                CurrentPage.ImageVisible = true;
                CurrentPage.Dirty = true;

                UpdateTitle();
            }
        }

        private void itmMakeStartupPage_Click(object sender, RoutedEventArgs e)
        {
            foreach (var p in Pages)
            {
                p.ShowOnStartup = false;
                p.Save();
            }

            CurrentPage.ShowOnStartup = true;
            CurrentPage.Save();

            //Update state of menu items
            itmMakeStartupPage.IsEnabled = false;

            MessageBox.Show(this, "Current page will be displayed on startup.", "Startup Page",
                MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void itmAddActionButton_Click(object sender, RoutedEventArgs e)
        {
            Controls.ActionButton button = new Controls.ActionButton()
            {
                Width = 300,
                Height = 200,
                Top = ContextMenuPosition.Y,
                Left = ContextMenuPosition.X
            };

            button.Click += new Plugin.ActionHandler(HandlePageButtonClick);

            PageContentPanel.Children.Add(button);

            Canvas.SetLeft(button, button.Left);
            Canvas.SetTop(button, button.Top);
            
            CurrentPage.Add(button);
        }

        private void itmAddMediaButton_Click(object sender, RoutedEventArgs e)
        {
            Controls.MediaButton button = new Controls.MediaButton()
            {
                Width = 300,
                Height = 200,
                Top = ContextMenuPosition.Y,
                Left = ContextMenuPosition.X
            };

            button.Click += new Plugin.ActionHandler(HandlePageButtonClick);

            PageContentPanel.Children.Add(button);

            Canvas.SetLeft(button, button.Left);
            Canvas.SetTop(button, button.Top);

            CurrentPage.Add(button);
        }

        private void itmSavePage_Click(object sender, RoutedEventArgs e)
        {
            if (ConfirmUserDataFolderExists())
            {
                FlushPageLayoutChanges(false);
                CurrentPage.Save();

                UpdateTitle();
            }
        }

        private void itmRemovePage_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show(this,
                "Are you sure you want to remove the current page?", "Remove Page",
                MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.No)
            {
                return;
            }

            Controls.Page pageToRemove = CurrentPage;

            //Update GotoPageAction page name references
            foreach (var page in Pages)
            {
                foreach (var control in page)
                {
                    if (control.ClickAction is Plugin.GotoPageAction)
                    {
                        Plugin.GotoPageAction action = control.ClickAction as Plugin.GotoPageAction;

                        if (action.GetParam("Page") == pageToRemove.Name)
                        {
                            control.ClickAction = new Plugin.EmptyAction();
                            page.Save();
                        }
                    }
                }
            }

            pageToRemove.DeleteFile();
            Pages.Remove(pageToRemove);

            //If only page deleted, create default page.
            if (Pages.Count == 0)
            {
                LoadPage(new Controls.Page("New Page")
                {
                    //If we deleted the startup page, make this page the startup page.
                    ShowOnStartup = pageToRemove.ShowOnStartup
                });

                MessageBox.Show(this, "Last page removed. Creating default page.", "Page Removed",
                    MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                LoadPage(Pages.First());
                //If we deleted the startup page, 
                //make the fist page in list the startup page.
                if (pageToRemove.ShowOnStartup)
                {
                    itmMakeStartupPage_Click(this, null);
                }
            }
        }
        #endregion

        #region Content Panel Events
        private void PageContentPanel_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            if (!EditMode)
            {
                e.Handled = true;
                return;
            }

            UpdatePageMenu();

            itmEditMode.Visibility = System.Windows.Visibility.Collapsed;
            itmEditModeSeparator.Visibility = itmEditMode.Visibility;

            ContextMenuPosition = new Point(e.CursorLeft, e.CursorTop);
            FocusTimer.Stop();
        }

        private void FocusTimer_Tick(object sender, EventArgs e)
        {
            //Rely on tab order
            TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
            UIElement keyboardFocus = Keyboard.FocusedElement as UIElement;

            if (keyboardFocus != null)
            {
                keyboardFocus.MoveFocus(tRequest);
            }
        }

        private void PressDownTimer_Tick(object sender, EventArgs e)
        {
            bool showEditModeItem = (Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == 
                (ModifierKeys.Control | ModifierKeys.Shift);

            PressDownTimer.Stop();

            if (!EditMode && !showEditModeItem)
                //Only show context menu if we are in edit-mode or the secret key is pressed
                return;

            itmEditMode.Visibility = showEditModeItem ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
            itmEditMode.Header = string.Format("Edit Mode {0}", EditMode ? "ON" : "OFF");
            itmEditMode.Foreground = new SolidColorBrush(EditMode ? Colors.Blue : Colors.Red);
            itmEditModeSeparator.Visibility = itmEditMode.Visibility;

            PageContentPanel.ContextMenu.IsOpen = true;
        }

        private void PageContentPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            PressDownTimer.Start();
            ContextMenuPosition = Mouse.GetPosition(PageContentPanel);
        }

        private void PageContentPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (PressDownTimer != null)
                PressDownTimer.Stop();
        }

        private void PageContentPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (PressDownTimer != null)
                PressDownTimer.Stop();
        }
        #endregion

        #region Resizable/Dragging Window Helpers
        private const int WM_SYSCOMMAND = 0x112;
        private HwndSource hwndSource;
        private IntPtr retInt = IntPtr.Zero;

        private void InitializeWindowSource(object sender, EventArgs e)
        {
            hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
            hwndSource.AddHook(new HwndSourceHook(WndProc));
        }
        
        public void DragWindow(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                if (WindowState == System.Windows.WindowState.Normal)
                {
                    WindowState = System.Windows.WindowState.Maximized;
                }
                else
                {
                    WindowState = System.Windows.WindowState.Normal;
                }

                return;
            }

            DragMove();

            Dispatcher.BeginInvoke(new ThreadStart(() =>
            {
                CurrentPage.Size = this.Width + "," + this.Height;
                CurrentPage.Location = this.Left + "," + this.Top;

                if (EditMode)
                {
                    CurrentPage.Dirty = true;
                    UpdateTitle();
                }
            }));
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            return IntPtr.Zero;
        }

        public enum ResizeDirection
        {
            Left = 1,
            Right = 2,
            Top = 3,
            TopLeft = 4,
            TopRight = 5,
            Bottom = 6,
            BottomLeft = 7,
            BottomRight = 8,
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private void ResizeWindow(ResizeDirection direction)
        {
            SendMessage(hwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
        }

        private void ResetCursor(object sender, MouseEventArgs e)
        {
            if (Mouse.LeftButton != MouseButtonState.Pressed)
            {
                this.Cursor = Cursors.Arrow;
            }
        }

        private void Resize(object sender, MouseButtonEventArgs e)
        {
            Rectangle clickedRectangle = sender as Rectangle;

            switch (clickedRectangle.Name)
            {
                case "top":
                    this.Cursor = Cursors.SizeNS;
                    ResizeWindow(ResizeDirection.Top);
                    break;
                case "bottom":
                    this.Cursor = Cursors.SizeNS;
                    ResizeWindow(ResizeDirection.Bottom);
                    break;
                case "left":
                    this.Cursor = Cursors.SizeWE;
                    ResizeWindow(ResizeDirection.Left);
                    break;
                case "right":
                    this.Cursor = Cursors.SizeWE;
                    ResizeWindow(ResizeDirection.Right);
                    break;
                case "topLeft":
                    this.Cursor = Cursors.SizeNWSE;
                    ResizeWindow(ResizeDirection.TopLeft);
                    break;
                case "topRight":
                    this.Cursor = Cursors.SizeNESW;
                    ResizeWindow(ResizeDirection.TopRight);
                    break;
                case "bottomLeft":
                    this.Cursor = Cursors.SizeNESW;
                    ResizeWindow(ResizeDirection.BottomLeft);
                    break;
                case "bottomRight":
                    this.Cursor = Cursors.SizeNWSE;
                    ResizeWindow(ResizeDirection.BottomRight);
                    break;
                default:
                    break;
            }

            Dispatcher.BeginInvoke(new ThreadStart(() =>
            {
                CurrentPage.Size = this.Width + "," + this.Height;
                CurrentPage.Location = this.Left + "," + this.Top;

                if (EditMode)
                {
                    CurrentPage.Dirty = true;
                    UpdateTitle();
                }
            }));
        }

        private void DisplayResizeCursor(object sender, MouseEventArgs e)
        {
            Rectangle clickedRectangle = sender as Rectangle;

            switch (clickedRectangle.Name)
            {
                case "top":
                    this.Cursor = Cursors.SizeNS;
                    break;
                case "bottom":
                    this.Cursor = Cursors.SizeNS;
                    break;
                case "left":
                    this.Cursor = Cursors.SizeWE;
                    break;
                case "right":
                    this.Cursor = Cursors.SizeWE;
                    break;
                case "topLeft":
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                case "topRight":
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case "bottomLeft":
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case "bottomRight":
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                default:
                    break;
            }
        }
        
        private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            CurrentPage.Location = this.Left + "," + this.Top;

            if (this.WindowState == System.Windows.WindowState.Maximized)
            {
                CurrentPage.Size = "Maximized";
            }
            else
            {
                CurrentPage.Size = this.Width + "," + this.Height;
            }

            if (EditMode)
            {
                CurrentPage.Dirty = true;
                UpdateTitle();
            }
        }
        #endregion

        #region Window Scaling Support
        public static readonly DependencyProperty ScaleValueProperty = DependencyProperty.Register("ScaleValue",
            typeof(double), 
            typeof(MainWindow), 
            new UIPropertyMetadata(1.0, new PropertyChangedCallback(OnScaleValueChanged), new CoerceValueCallback(OnCoerceScaleValue))
        );

        private static object OnCoerceScaleValue(DependencyObject o, object value) {
            MainWindow mainWindow = o as MainWindow;
            if (mainWindow != null)
                return mainWindow.OnCoerceScaleValue((double)value);
            else
                return value;
        }

        private static void OnScaleValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
            MainWindow mainWindow = o as MainWindow;
            if (mainWindow != null)
                mainWindow.OnScaleValueChanged((double)e.OldValue, (double)e.NewValue);
        }

        protected virtual double OnCoerceScaleValue(double value) {
            if (double.IsNaN(value))
                return 1.0f;

            value = Math.Max(0.1, value);
            return value;
        }

        protected virtual void OnScaleValueChanged(double oldValue, double newValue) {

        }

        public double ScaleValue {
            get {
                return (double)GetValue(ScaleValueProperty);
            }
            set {
                SetValue(ScaleValueProperty, value);
            }
        }

        private void MainGrid_SizeChanged(object sender, EventArgs e) {
            CalculateScale();
        }

        private void CalculateScale() {
            double yScale = ActualHeight / 600f;
            double xScale = ActualWidth / 800f;
            double value = Math.Min(xScale, yScale);
            ScaleValue = (double)OnCoerceScaleValue(myMainWindow, value);
        }
        #endregion
    }
}
